#include "gd32_sw_i2c.h"

/* ??I2C?????GPIO??, ?????????4?????????SCL?SDA??? */
#define GPIO_PORT_I2C	GPIOB			/* GPIO?? */
#define I2C_SCL_PIN		GPIO_PIN_6			/* ???SCL????GPIO */
#define I2C_SDA_PIN		GPIO_PIN_7			/* ???SDA????GPIO */

/* ????SCL?SDA??,??????????????? */
#define I2C_SCL_OUTPUT()	//gpio_init(GPIO_PORT_I2C,GPIO_MODE_OUT_OD,GPIO_OSPEED_50MHZ,I2C_SCL_PIN)
#define I2C_SCL_INPUT()		//gpio_init(GPIO_PORT_I2C,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,I2C_SCL_PIN)
#define I2C_SDA_OUTPUT()	//gpio_init(GPIO_PORT_I2C,GPIO_MODE_OUT_OD,GPIO_OSPEED_50MHZ,I2C_SDA_PIN)
#define I2C_SDA_INPUT()		//gpio_init(GPIO_PORT_I2C,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,I2C_SDA_PIN)

#define I2C_SCL_1()  gpio_bit_set(GPIO_PORT_I2C, I2C_SCL_PIN)		/* SCL = 1 */
#define I2C_SCL_0()  gpio_bit_reset(GPIO_PORT_I2C, I2C_SCL_PIN)		/* SCL = 0 */

#define I2C_SDA_1()  gpio_bit_set(GPIO_PORT_I2C, I2C_SDA_PIN)		/* SDA = 1 */
#define I2C_SDA_0()  gpio_bit_reset(GPIO_PORT_I2C, I2C_SDA_PIN)		/* SDA = 0 */

#define I2C_SDA_READ()  gpio_input_bit_get(GPIO_PORT_I2C, I2C_SDA_PIN)	/* ?SDA???? */

/*
*********************************************************************************************************
*	? ? ?: i2c_Delay
*	????: I2C?????,??400KHz
*	?    ?:?
*	? ? ?: ?
*********************************************************************************************************
*/
static void i2c_Delay(void)
{
	//uint8_t i;

	//for (i = 0; i < 50; i++);
	__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();
	__nop();__nop();__nop();__nop();__nop();__nop();
	
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
	
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
//	__nop();__nop();__nop();__nop();__nop();__nop();
}

/*
*********************************************************************************************************
*	? ? ?: I2C_Start
*	????: CPU??I2C??????
*	?    ?:?
*	? ? ?: ?
*********************************************************************************************************
*/
void I2C_Start(void)
{
	/* ?SCL????,SDA?????????I2C?????? */
	
	I2C_SCL_OUTPUT();
	I2C_SDA_OUTPUT();
	
	I2C_SDA_1();
	I2C_SCL_1();
	i2c_Delay();
	I2C_SDA_0();
	i2c_Delay();
	I2C_SCL_0();
	i2c_Delay();
}

/*
*********************************************************************************************************
*	? ? ?: I2C_Start
*	????: CPU??I2C??????
*	?    ?:?
*	? ? ?: ?
*********************************************************************************************************
*/
void I2C_Stop(void)
{
	I2C_SCL_OUTPUT();
	I2C_SDA_OUTPUT();

	/* ?SCL????,SDA?????????I2C?????? */
	I2C_SDA_0();
	I2C_SCL_1();
	i2c_Delay();
	I2C_SDA_1();
}

/*
*********************************************************************************************************
*	? ? ?: I2C_Send_Byte
*	????: CPU?I2C??????8bit??
*	?    ?:_ucByte : ???????
*	? ? ?: ?
*********************************************************************************************************
*/
void I2C_Send_Byte(uint8_t _ucByte)
{
	uint8_t i;

	/* ????????bit7 */
	for (i = 0; i < 8; i++)
	{		
		if (_ucByte & 0x80)
		{
			I2C_SDA_1();
		}
		else
		{
			I2C_SDA_0();
		}
		i2c_Delay();
		I2C_SCL_1();
		i2c_Delay();	
		I2C_SCL_0();
		if (i == 7)
		{
			 I2C_SDA_1(); // ????
		}
		_ucByte <<= 1;	/* ????bit */
		i2c_Delay();
	}
}

/*
*********************************************************************************************************
*	? ? ?: I2C_Read_Byte
*	????: CPU?I2C??????8bit??
*	?    ?:?
*	? ? ?: ?????
*********************************************************************************************************
*/
uint8_t I2C_Read_Byte(uint8_t ack)
{
	uint8_t i;
	uint8_t value;

	/* ???1?bit????bit7 */
	I2C_SDA_INPUT();	// set data input	
	i2c_Delay();
	value = 0;
	for (i = 0; i < 8; i++)
	{
		value <<= 1;
		//I2C_SCL_1();
		//i2c_Delay();
		if (I2C_SDA_READ())
		{
			value++;
		}
		I2C_SCL_1();
		i2c_Delay();
		I2C_SCL_0();
		i2c_Delay();
	}
	
	I2C_SDA_OUTPUT();	// set data output	
	i2c_Delay();
	if(ack==0)
		i2c_NAck();
	else
		i2c_Ack();
	return value;
}

/*
*********************************************************************************************************
*	? ? ?: I2C_Wait_Ack
*	????: CPU??????,??????ACK????
*	?    ?:?
*	? ? ?: ??0??????,1???????
*********************************************************************************************************
*/
uint8_t I2C_Wait_Ack(void)
{
	uint8_t re;

	I2C_SDA_1();	/* CPU??SDA?? */
	I2C_SDA_INPUT();	//set data input
	i2c_Delay();
	I2C_SCL_1();	/* CPU??SCL = 1, ???????ACK?? */
	i2c_Delay();
	if(I2C_SDA_READ())	/* CPU??SDA???? */
	{
		re = 1;
	}
	else
	{
		re = 0;
	}
	I2C_SCL_0();
	I2C_SDA_OUTPUT();	//set data input
	i2c_Delay();
	return re;
}

/*
*********************************************************************************************************
*	? ? ?: i2c_Ack
*	????: CPU????ACK??
*	?    ?:?
*	? ? ?: ?
*********************************************************************************************************
*/
void i2c_Ack(void)
{
	I2C_SDA_0();	/* CPU??SDA = 0 */
	i2c_Delay();
	I2C_SCL_1();	/* CPU??1??? */
	i2c_Delay();
	I2C_SCL_0();
	i2c_Delay();
	I2C_SDA_1();	/* CPU??SDA?? */
}

/*
*********************************************************************************************************
*	? ? ?: i2c_NAck
*	????: CPU??1?NACK??
*	?    ?:?
*	? ? ?: ?
*********************************************************************************************************
*/
void i2c_NAck(void)
{
	I2C_SDA_1();	/* CPU??SDA = 1 */
	i2c_Delay();
	I2C_SCL_1();	/* CPU??1??? */
	i2c_Delay();
	I2C_SCL_0();
	i2c_Delay();	
}

/*
*********************************************************************************************************
*	? ? ?: i2c_GPIO_Config
*	????: ??I2C???GPIO,????IO?????
*	?    ?:?
*	? ? ?: ?
*********************************************************************************************************
*/
void i2c_GPIO_Config(void)
{
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_init(GPIO_PORT_I2C, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, I2C_SCL_PIN|I2C_SDA_PIN);
	/* ???????, ??I2C????????????? */
	I2C_Stop();
}

/*
*********************************************************************************************************
*	? ? ?: i2c_CheckDevice
*	????: ??I2C????,CPU???????,??????????????????
*	?    ?:_Address:???I2C????
*	? ? ?: ??? 0 ????, ??1??????
*********************************************************************************************************
*/
uint8_t i2c_CheckDevice(uint8_t _Address)
{
	uint8_t ucAck;

	i2c_GPIO_Config();		/* ??GPIO */
	I2C_Start();		/* ?????? */
	/* ??????+????bit(0 = w, 1 = r) bit7 ?? */
	I2C_Send_Byte(_Address|I2C_WR);
	ucAck = I2C_Wait_Ack();	/* ?????ACK?? */
	I2C_Stop();			/* ?????? */

	return ucAck;
}


uint8_t qst_sw_writereg(uint8_t slave, uint8_t reg_add, uint8_t reg_dat)
{
	I2C_Start();
	I2C_Send_Byte(slave|I2C_WR);
	if(I2C_Wait_Ack())
	{
		return 0;
	}
	I2C_Send_Byte(reg_add);	
	if(I2C_Wait_Ack())
	{
		return 0;
	}
	I2C_Send_Byte(reg_dat);	
	if(I2C_Wait_Ack())
	{
		return 0;
	}
	I2C_Stop();

	return 1;
}

uint8_t qst_sw_readreg(uint8_t slave, uint8_t reg_add, uint8_t *buf, uint8_t num)
{
	//uint8_t ret;
	uint8_t i;

	I2C_Start();
	I2C_Send_Byte(slave|I2C_WR);
	if(I2C_Wait_Ack())
	{
		return 0;
	}
	I2C_Send_Byte(reg_add);
	if(I2C_Wait_Ack())
	{
		return 0;
	}

	I2C_Start();
	I2C_Send_Byte(slave|I2C_RD);
	if(I2C_Wait_Ack())
	{
		return 0;
	}

	for(i=0;i<(num-1);i++){
		*buf=I2C_Read_Byte(1);
		buf++;
	}
	*buf=I2C_Read_Byte(0);
	I2C_Stop();

	return 1;
}

